//
//  ViewController.swift
//  BasicExtensions
//
//  Created by fanxiaoxin_1987@126.com on 11/04/2021.
//  Copyright (c) 2021 fanxiaoxin_1987@126.com. All rights reserved.
//

import UIKit
import BasicExtensions
import UICreate
import CommonCrypto

class ViewController: UIViewController {
    
    var ob1: NSKeyValueObservation?
    var ob2: NSKeyValueObservation?
    var ob3: NSKeyValueObservation?
    class cls_test: CustomStringConvertible {
        let flag: Int
        init(_ flag: Int) {
            print("I'm a class for test: \(flag)")
            self.flag = flag
        }
        var description: String {
            return "desc for test: \(self.flag)"
        }
    }
    var opValues: [String: cls_test] = [:]
    let hexs:[UInt8] = "0123456789abcdef".unicodeScalars.map({ UInt8($0.value) })
    func hash2(for text: String) -> String {
        let utf8 = text.cString(using: .utf8)
        let length = Int(CC_MD5_DIGEST_LENGTH)
        var digest = [UInt8](repeating: 0, count: length)
        CC_MD5(utf8, CC_LONG(utf8!.count - 1), &digest)
        let pointer = UnsafeMutablePointer<UInt8>.allocate(capacity: length * 2)
        defer {
            pointer.deallocate()
        }
        for i in 0..<length {
            pointer[i * 2] = hexs[Int(digest[i] >> 4)]
            pointer[i * 2 + 1] = hexs[Int((digest[i] << 4) >> 4)]
        }
        return .init(cString: pointer)
    }
    func hash3(for text: String) -> String {
        let utf8 = text.cString(using: .utf8)
        var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
        CC_MD5(utf8, CC_LONG(utf8!.count - 1), &digest)
        return digest.reduce("") { $0 + String(format:"%02X", $1) }
    }
    struct GroupItem {
        let value: Int
        let gb: Int
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let groupTest: [GroupItem] = [.init(value: 1, gb: 1), .init(value: 2, gb: 1), .init(value: 3, gb: 3), .init(value: 4, gb: 2), .init(value: 5, gb: 3), .init(value: 6, gb: 1), .init(value: 7, gb: 2)]

        print("GROUP \(groupTest.group(by: \.gb))")
        print("GROUP \(groupTest.group { $0.gb })")
        
        print("SORTED \(groupTest.sorted(by: <, for: \.value))")
        
        let estr1 = ""
        print("FUCK \(estr1 ??? "i'm empty")")
        let estr2 = "Not Empty"
        print("FUCK \(estr2 ??? "i'm empty")")
        let estr3: String? = nil
        print("FUCK \(estr3 ??? "i'm empty")")
        let estr4: String? = ""
        print("FUCK \(estr4 ??? "i'm empty")")
        let estr5: String? = "Not Empty"
        print("FUCK \(estr5 ??? "i'm empty")")
        let estr6: String? = " "
        print("FUCK \(estr6 ??? "i'm empty")")
        
        let texts = [String].init(repeating: "ABCD", count: 1000)
        var time = Date()
        for i in 0..<1000 {
            _ = self.hash2(for: texts[i])
        }
        print("FUCK \(floor(-time.timeIntervalSinceNow * 1000000))")
        time = Date()
        for i in 0..<1000 {
            _ = self.hash3(for: texts[i])
        }
        print("FUCK \(floor(-time.timeIntervalSinceNow * 1000000))")
        
        print([3,5] ~= [3,4,5])
        let data: Data? = "34".data(using: .utf8)
        
        let a = data ??> { String.init(data:$0, encoding:.utf8) } ??> { Int($0) }
        print("HeiHei-\(a)")
        let str1: String? = "FUCK"
        let str2: String? = " YOU"
        let str3: String? = " Bitch"
        let b = (str1, str2, str3) ??> { $0 + $1 + $2 }
        print("HeiHei-\(b)")
        
        str1 ??> {
            print($0)
            print($0 + " ME")
        }
        
        var opValue1: cls_test? = nil//cls_test(2)
        let opValue2: cls_test? = nil//cls_test(3)
//        self.opValues["A"] = cls_test(1)
        print(self.opValues["A"])
        print(opValue1)
        print(opValue2)
        let opValue = self.opValues["A"] ??< opValue1 ??< opValue2 ?? .init(4)
        print(opValue)
        print(self.opValues["A"])
        print(opValue1)
        print(opValue2)
        
        let arr = [1,2,3,4,2,2,3,1,5]
        print(arr.byDistinctFirst())
        print(arr.byDistinctLast())
        
        var dic: [String: Int] = [:]
        dic["a"] = 4
        let dicValue = dic["a"] ?? {
            let value = 3
            dic["a"] = value
            print("dic block")
            return value
        }()
        print(dicValue)
        
        // Do any additional setup after loading the view, typically from a nib.
        var rect = CGRect.init(1, 2, 3, 4)
        rect += CGPoint.init(3)
        let v = UIView()
        v.frame += CGSize.init(5)
        let i: Int = 3
        
        let point: CGPoint = [5, 10]
        let size: CGSize = [10, 20]
        let rect2 = point + size
        var s = size
        s += CGFloat(3)
        print(rect2)
        let rect3: CGRect = [7, 8, 9 ,10]
        print(rect3)
        var rect4: CGRect = rect2 + [3, 4, 5, 5]
        print(rect4)
        let size2 = size + [5, 7]
        print(size2)
        self.view.frame = [7, 8, 9, 10]
        
        print("\(self.appearState.rawValue)")
        print(self.isFirstAppearance)
        self.ob1 = self.observe(\.appearState, options: [.new, .old, .initial, .prior]) { [weak self] c, v in
            print("chage: \(self?.appearState.rawValue)")
        }
        self.ob3 = self.observe(\.isFirstAppearance, options: [.new, .old, .initial, .prior]) { c, v in
            print("chage: \(v)")
        }
        
        let label = UILabel(.text("TEST"))
        self.ob2 = self.view.observe(\.isLayingOut, options: .new, changeHandler: { view, value in
            print("v chage: \(value)")
        })
        let button = UIButton(.text("测试"), .event(self, #selector(self.onTest)), .color(.systemBlue))
        
        let image = UIImage.create(color: .red, size: 200).by(.corner(radius: 15, corners: [.topLeft, .bottomRight], borderWidth: 1, borderColor: .blue, borderLineJoin: .miter),
                                                              .resize([150,100]),
                                                              .clip([-50, -50, 100, 100]),
                                                              .merger(.create(color: .green, size: 50), at: -100),
                                                              .rotate(90))
        self.view.build {
            label.layout(.center)
            button.layout(.bottomTop(20), .centerX, .size(80, 44))
            UIImageView(.image(image)).layout(.bottomTop(20), .centerX)
        }
        
        let test = self.extend.object(for: "Test", createIfNil: Test(v: 3))
        print("test \(test.value)")
        test.value = 2
        print("test \(test.value)")
        let test2 = self.extend.object(for: "Test", createIfNil: Test(v: 5))
        print("test \(test2.value)")
        
        let reg = "<tag>(?<a>.*?)</tag>"
        let testText = "<tag>abc</tag>eee<tag>ffff</tag>"
        let attr = NSMutableAttributedString(string: testText, attributes: [.font: UIFont.boldSystemFont(ofSize: 20), .foregroundColor: UIColor.systemBlue])
        attr.addAttributes(.foregroundColor, value: UIColor.systemRed, pattern: reg, replacing: 1)
        label.attributedText = attr
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print("\(self.appearState.rawValue)")
        print(self.isFirstAppearance)
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("\(self.appearState.rawValue)")
        print(self.isFirstAppearance)
    }
    @objc func onTest() {
        let c = SubViewController()
        self.navigationController?.pushViewController(c, animated: true)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
class Test {
    var value = 1
    init(v: Int) {
        self.value = v
        print("i'm inited")
    }
}
class TestView: UIView {
    override func layoutSubviews() {
        
    }
}
/// 数据缓存池
public class DataCachePool {
    struct Value {
        var duration: TimeInterval {
            didSet {
                if let storage = self.storage {
                    let offset = duration - oldValue
                    self.storage = (data: storage.data, expirationDate: storage.expirationDate.addingTimeInterval(offset))
                }
            }
        }
        var storage: (data: Any, expirationDate: Date)? = nil
        
        
        var data: Any? {
            get {
                isValid ? storage?.data : nil
            }
            set {
                storage = newValue.map { newValue in
                    let expirationDate = Date().addingTimeInterval(duration)
                    return (newValue, expirationDate)
                }
            }
        }
        
        var isValid: Bool {
            guard let storage = storage else { return false }
            return storage.expirationDate >= Date()
        }
    }
    public static let shared = DataCachePool()
    private var values: [String: Value] = [:]
    public subscript(_ key: String) -> Any? {
        get {
            return self.values[key]?.data
        }
        set {
            if var value = self.values[key] {
                value.data = newValue
                self.values[key] = value
            }
        }
    }
    /// 设置缓存时间
    public func setCacheTime(_ time: TimeInterval, for key: String) {
        if var value = self.values[key] {
            value.duration = time
            self.values[key] = value
        }else{
            self.values[key] = .init(duration: time)
        }
    }
    /// 获取缓存时间
    public func cacheTime(for key: String) -> TimeInterval {
        return self.values[key]?.duration ?? 0
    }
}
//public protocol DataCacheable {
////    associatedtype DataType
////    func request(_ completion: (Result<DataType, Error>) -> Void)
//    var cacheKey: String { get }
//}
///// 数据缓存池
//fileprivate let __dataCachePool = DataCachePool()
//extension DataCacheable {
//    /// 缓存时长
//    public var cacheDuration: TimeInterval {
//        get {
//            return __dataCachePool.cacheTime(for: self.cacheKey)
//        }
//        set {
//            __dataCachePool.setCacheTime(newValue, for: self.cacheKey)
//        }
//    }
//    /// 设置缓存超时
//    public func setNeedRefreshCache() {
//        __dataCachePool[self.cacheKey] = nil
//    }
//    /// 直接刷新缓存
//    public func refreshCache() {
//        self.request { result in
//            switch result {
//            case let .success(data):
//                __dataCachePool[self.cacheKey] = data
//            default: break
//            }
//        }
//    }
//    /// 刷新缓存若超时
//    public func refreshCacheIfNeeded() {
//        if __dataCachePool[self.cacheKey] == nil {
//            self.refreshCache()
//        }
//    }
//    /// 先取缓存的数据(若存在缓存)再去更新数据(若缓存超时)
//    public func dataBeforeRequest(_ completion: (Result<DataType, Error>) -> Void) {
//
//    }
//    /// 先更新数据(若缓存超时)再返回结果
//    public func dataAfterRequest(_ completion: (Result<DataType, Error>) -> Void) {
//
//    }
//}
public protocol ApiBaseType {
    var host: String { get }
    var method: String { get }
    var timeout: TimeInterval { get }
    var header: [String: String]? { get }
    var userAgent: String? { get }
    var dataProvider: ApiDataProviderType { get }
}
public protocol ApiType: ApiBaseType {
    var base: ApiBaseType { get }
    var path: String { get }
}
extension ApiBaseType {
    public var method: String { return "GET" }
    public var header: [String: String]? { return nil }
    public var userAgent: String? { return nil }
}
extension ApiType {
    public var host: String { return self.base.host }
    public var method: String { return self.base.method }
    public var timeout: TimeInterval { return self.base.timeout }
    public var header: [String: String]? { return self.base.header }
}
public protocol ResponseApiType {
    associatedtype ResponseModelType
}

/// 接口数据提供者
public protocol ApiDataProviderType {
    
}

protocol TESTDelegate {
    
}
protocol Weakable {
    
}
func notNil<T, T2>(_ t: T?, _ block: (T) -> T2) -> T2? {
    if let t = t {
        return block(t)
    }
    return nil
}
extension Weakable {
    var isObject: Bool {
//        Optional<Int>
//        let a = notNil(data) { notNil(String(data: $0, encoding: .utf8)) { _ in  String(data: Data(), encoding: .utf8) } } ???? ""
        
        return self is AnyObject
    }
}
//struct WeakableDelegate<T> {
//    var structDelegate: T?
//    weak var classDelegate: (T & AnyObject)?
//}
//class XX {
//    weak var delegate: TESTDelegate?
//}

